package com.hibernate.hrm.dao;

import com.hibernate.hrm.entity.Contract;
import com.hibernate.hrm.entity.Department;
import com.hibernate.hrm.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;

public interface ContractRepository extends JpaRepository<Contract, Integer> {

    @Query("SELECT c FROM Contract c WHERE " +
            "(:departmentId IS NULL OR c.department.departmentID = :departmentId) AND " +
            "(:contractType IS NULL OR c.contractType = :contractType) AND " +
            "(:status IS NULL OR c.status = :status)")
    Page<Contract> findByFilters(
            @Param("departmentId") Integer departmentId,
            @Param("contractType") Contract.ContractType contractType,
            @Param("status") Contract.ContractStatus status,
            Pageable pageable);

    @Query("SELECT c FROM Contract c WHERE " +
            "c.department IN :departments AND " +
            "(:contractType IS NULL OR c.contractType = :contractType) AND " +
            "(:status IS NULL OR c.status = :status)")
    Page<Contract> findByDepartments(
            @Param("departments") List<Department> departments,
            @Param("contractType") Contract.ContractType contractType,
            @Param("status") Contract.ContractStatus status,
            Pageable pageable);

    @Query("SELECT c FROM Contract c WHERE " +
            "(c.signingPartyA.userId = :userId OR c.signingPartyB.userId = :userId) AND " +
            "(:contractType IS NULL OR c.contractType = :contractType) AND " +
            "(:status IS NULL OR c.status = :status)")
    Page<Contract> findByUser(
            @Param("userId") Integer userId,
            @Param("contractType") Contract.ContractType contractType,
            @Param("status") Contract.ContractStatus status,
            Pageable pageable);

    @Modifying
    @Query("UPDATE Contract c SET " +
            "c.contractName = :contractName, " +
            "c.contractType = :contractType, " +
            "c.signingPartyA.userId = :signingPartyAId, " +
            "c.signingPartyB.userId = :signingPartyBId, " +
            "c.effectiveDate = :effectiveDate, " +
            "c.expiryDate = :expiryDate, " +
            "c.department.departmentID = :departmentId, " +
            "c.isTransferable = :isTransferable, " +
            "c.penaltyRate = :penaltyRate, " +
            "c.workPosition = :workPosition, " +
            "c.workLocation = :workLocation, " +
            "c.entrustContent = :entrustContent, " +
            "c.entrustScope = :entrustScope, " +
            "c.serviceContent = :serviceContent, " +
            "c.updateTime = CURRENT_TIMESTAMP " +
            "WHERE c.contractId = :contractId")
    void updateContract(
            @Param("contractId") Integer contractId,
            @Param("contractName") String contractName,
            @Param("contractType") Contract.ContractType contractType,
            @Param("signingPartyAId") Integer signingPartyAId,
            @Param("signingPartyBId") Integer signingPartyBId,
            @Param("effectiveDate") LocalDate effectiveDate,
            @Param("expiryDate") LocalDate expiryDate,
            @Param("departmentId") Integer departmentId,
            @Param("isTransferable") Boolean isTransferable,
            @Param("penaltyRate") BigDecimal penaltyRate,
            @Param("workPosition") String workPosition,
            @Param("workLocation") String workLocation,
            @Param("entrustContent") String entrustContent,
            @Param("entrustScope") String entrustScope,
            @Param("serviceContent") String serviceContent
    );
}
